package com.example.java.base.reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * ReflectDemo01:反射获取类相关(基本操作)
 *
 * @author zhangxiaoxiang
 * @date 2020/11/3
 */
public class ReflectTest {
    /**
     * 通过反射获取类(获取反射对象的3种方式 意区别,有的需要抛异常有的不需要)
     */
    public static void demo01() {
        try {
            Class<?> perClazz = Class.forName("com.example.java.base.reflect.Person");
            System.out.println("方式1===>通过Class.forName(\"全类名\")\t" + perClazz);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Class<?> perClazz2 = Person.class;
        System.out.println("方式2===>类名.class\t" + perClazz2);

        Person per = new Person();
        Class<?> perClazz3 = per.getClass();
        System.out.println("方式3===>对象.getClass()\t" + perClazz3);
    }


    /**
     * 为了方便,这里定义一个方法获取反射,方便后面测试,这里使用的方式一为示例
     *
     * @return 获取到的反射对象
     */
    public static Class<?> getClassTest() {
        //Class入口
        Class<?> perClazz = null;
        try {
            perClazz = Class.forName("com.example.java.base.reflect.Person");
            return perClazz;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取方法(所有的都可以)
     */
    public static void demo02() throws IllegalAccessException, InstantiationException {
        //Class入口
        Class<?> perClazz = getClassTest();
        //获取所有的 公共的方法(1.本类 以及 父类、接口中的所有方法  2.符合访问修饰符规律),注意空指针
        System.out.println("===================================获取方法(所有的都可以)===========================");
        Method[] methods = Objects.requireNonNull(perClazz).getMethods();
        System.out.println("公共的方法==========");
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("所有的方法==========");
        //获取当前类的所有方法（1.只能是当前类   2.忽略访问修饰符限制）
        Method[] declaredMethods = perClazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        System.out.println("===================================获取所有的接口===========================");

        Class<?>[] interfaces = perClazz.getInterfaces();
        for (Class<?> inter : interfaces) {
            System.out.println(inter);
        }
        System.out.println("===================================获取所有的父类===========================");
        Class<?> superclass = perClazz.getSuperclass();
        System.out.println(superclass);
        System.out.println("===================================获取所有的构造方法===========================");
        Constructor<?>[] constructors = perClazz.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("===================================获取所有的构造方法===========================");
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("===================================获取所有的属性(公共和私有等)===========================");
        System.out.println("所有公共属性====");
        Field[] fields = perClazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("所有属性  (属性的 ：公共属性 所有属性的区别 同“方法”)====");
        Field[] declaredFields = perClazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        System.out.println("============================获取当前反射所代表类(接口) 的对象(实例)===========================");
        Object instance = perClazz.newInstance();
        Person per = (Person) instance;
        per.interface2Method();
    }

    /**
     * 测试
     *
     * @throws InstantiationException 异常1
     * @throws IllegalAccessException 异常2
     */
    @Test
    public void test2() throws InstantiationException, IllegalAccessException {
        System.out.println("************************获取反射对象的3种方式************************");
        demo01();
        System.out.println("************************获取反射其他信息********************************");
        demo02();
    }
}